The Drawing Service

The Drawing Service is a web service who supports the storage and retrival of drawings. a drawing is a collection of shapes, with two shapes supported - a circle and a square.

The Drawing Service example demostraits the use of the J2XB module to support

  • Inheritence - Shape class, subclassed by Square and Circle.
  • Collections - the Drawing class has a list of shapes.
  • Factories - the Shape instances are created only using a factory method in the drawing class
  • Exceptions - the drawing service exposes two exceptions

The following figure shows the class diagram for the Drawing Service

Class Diagram of the Drawing Service

The Drawing class represents the drawings that are stored by the Drawing Service. Each drawing contains a list of shapes and a factory method to create new shapes in the context of the drawing.

The Shape class represents one abstract shape with one size member. It is subclasses by the Circle and Square classes, each adding new attributes specific for that shape class.

The Service Class

The code for the service class is

public class DrawingService {

  private Map<String, Drawing> drawingMap = new HashMap<String, Drawing>();

  public void addDrawing(Drawing drawing, String name) {
    drawingMap.put(name, drawing);
  }

  public Drawing getDrawing(String name) throws DrawingException, SecondDrawingException {
    if (!contains(name))
      throw new DrawingException(name);
    return drawingMap.get(name);
  }

  public boolean contains(String name) {
    return drawingMap.containsKey(name);
  }

  public int getSize() {
    return drawingMap.size();
  }
  
  public Set<String> getNames() {
    return drawingMap.keySet();
  }
}

As you can see, the service class is just a regular POJO that we expose as a web service. Notice that it, by itself, does not seem to have anything special that Axis2 does not support - except for the getNames method.

The getNames method returns a Set , a datatype that is not supported by Axis2. The J2XB Axis2 module adds support for this type, as well as for List types.

The Drawing class

The code for the drawing class is

@MOPersistentBean(xmlName = "Drawing")
@MOXmlGlobalType("DrawingType")
@MOXmlNamespace(value = "http://example.abra.com/inheritence/shapes", preferedPrefix = "ex14")
@MOSeeAlso({Square.class, Circle.class})
public class Drawing {
  private List<Shape> shapes = new ArrayList<Shape>();

  @MOProperty
  @MOXmlGlobalBeanRef
  @MOConstructionDescriptor(
      factoryMethod = "createShapes",
      constructorArgs = {
      @MOConstructorArg(sourceProperty = MOConstructorArg.CLASS_PROPERTY, sourcePropertyOf = SourcePropertyOf.constructedInstance),
      @MOConstructorArg(sourceProperty = "size", sourcePropertyOf = SourcePropertyOf.constructedInstance)
      }
  )
  public List<Shape> getShapes() {
    return shapes;
  }

  public static Shape createShapes(Class classToCreate, int size) {
    Shape shape;
    if (classToCreate == com.abra.j2xb.axis2.example.Square.class)
      shape = new Square();
    else
      shape = new Circle();
    shape.setSize(size);
      return shape;
    }
  }
}

The Drawing class shows usage of some of the features that J2XB brings to the Axis2 world.

The annotations on the Drawing class define the name of the XML element representing the class, as well as a global XML type for the class. In addition, the MOSeeAlso annotation tells J2XB to map two additional classes that cannot be automatically discovered by inspecting the Drawing class (the Shape class can be discovered and is automatically included in the J2XB mapping).

The annotations on the shapes property (the getShapes method) tells J2XB to map the property, use a reference to a globally defined XML element (for the Shape class) and to use a factory method createShapes to create instances of the Shape class when reading the instances from XML. Notice that the factory method assigns the size property of the Shape class - if we did not assign this value in the factory method, we could refrain from using a factory method at all. J2XB supports inheritence without any requirement for factory methods.

The Shape class

The code for the Shape class is

@MOPersistentBean(xmlName = "Shape")
@MOXmlGlobalType("ShapeType")
@MOXmlNamespace(value = "http://example.abra.com/inheritence/shapes", preferedPrefix = "ex14")
public abstract class Shape {
  private int size;

  @MOProperty
  public int getSize() {
    return size;
  }

  public void setSize(int size) {
    this.size = size;
  }
}

The Shape class is an abstract class with two sub-classes. Notice that again we define the XML Element and type names (defining a global XML type is mandatory for inheritence trees due to the XML Schema specification). Aside from the class beeing annotated using J2XB annotations, there is nothing special about it.

The Square and Circle classes

The code for the Square and Circle classes is

@MOPersistentBean(xmlName = "Circle")
@MOXmlGlobalType("CircleType")
@MOXmlNamespaceRef(Shape.class)
public class Circle extends Shape {
        private int radius;

        @MOProperty
        public int getRadius() {
                return radius;
        }

        public void setRadius(int radius) {
                this.radius = radius;
        }
}
@MOPersistentBean(xmlName = "Square")
@MOXmlGlobalType("SquareType")
@MOXmlNamespaceRef(Shape.class)
public class Square extends Shape {
        private int height;
        private int width;

        @MOProperty
        public int getHeight() {
                return height;
        }

        public void setHeight(int height) {
                this.height = height;
        }

        @MOProperty
        public int getWidth() {
                return width;
        }

        public void setWidth(int width) {
                this.width = width;
        }
}

Again, those two classes have nothing special except the J2XB annotations. One thing to notice is that we have used the MOXmlNamespaceRef annotation to define the namespace for those classes instead of the MOXmlNamespace annotation. The MOXmlNamespaceRef annotation allows to define that one class is in the same namespace at another class, without repeating the namespace itself.

The WSDL created for the Drawing Service

The WSDL below was generated using J2XB and copied from the Axis2 web application.

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ex14="http://example.abra.com/inheritence/shapes" xmlns:ns0="http://lang.java_proxy" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:ax25="http://example.axis2.j2xb.abra.com/xsd" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:axis2="http://axis2.j2xb.abra.com/example/drawingService" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:ax27="http://util.java/xsd" xmlns:ns="http://axis2.j2xb.abra.com/example/drawing" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://axis2.j2xb.abra.com/example/drawingService">
  <wsdl:documentation>DrawingService</wsdl:documentation>
  <wsdl:types>
    <xs:schema xmlns:ns1="http://lang.java_proxy" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://example.abra.com/inheritence/shapes">
      <xs:import namespace="http://lang.java_proxy"/>
      <xs:element abstract="true" name="Shape" type="ex14:ShapeType"/>
      <xs:element name="Drawing" type="ex14:DrawingType"/>
      <xs:element name="DrawingFault" substitutionGroup="ns1:Throwable" type="ex14:DrawingFaultType"/>
      <xs:element name="Square" substitutionGroup="ex14:Shape" type="ex14:SquareType"/>
      <xs:element name="Circle" substitutionGroup="ex14:Shape" type="ex14:CircleType"/>
      <xs:element name="SecondDrawingFault" substitutionGroup="ns1:Throwable" type="ex14:SecondDrawingFaultType"/>
      <xs:complexType name="CircleType">
        <xs:complexContent>
          <xs:extension base="ex14:ShapeType">
            <xs:sequence>
              <xs:element name="radius" type="xs:int"/>
            </xs:sequence>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
      <xs:complexType name="ShapeType">
        <xs:sequence>
          <xs:element name="size" type="xs:int"/>
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="SecondDrawingFaultType">
        <xs:complexContent>
          <xs:extension base="ns1:ThrowableType">
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
              <xs:element name="size" type="xs:int"/>
            </xs:sequence>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
      <xs:complexType name="SquareType">
        <xs:complexContent>
          <xs:extension base="ex14:ShapeType">
            <xs:sequence>
              <xs:element name="height" type="xs:int"/>
              <xs:element name="width" type="xs:int"/>
            </xs:sequence>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
      <xs:complexType name="DrawingType">
        <xs:sequence>
          <xs:element maxOccurs="unbounded" minOccurs="0" ref="ex14:Shape"/>
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="DrawingFaultType">
        <xs:complexContent>
          <xs:extension base="ns1:ThrowableType">
            <xs:sequence>
              <xs:element name="name" type="xs:string"/>
            </xs:sequence>
          </xs:extension>
        </xs:complexContent>
      </xs:complexType>
    </xs:schema>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://axis2.j2xb.abra.com/example/drawing">
      <xs:import namespace="http://example.abra.com/inheritence/shapes"/>
      <xs:element name="getSizeResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="return" type="xs:int"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="addDrawing">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="drawing" type="ex14:DrawingType"/>
            <xs:element name="name" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="getNamesResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element maxOccurs="unbounded" minOccurs="0" name="return" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="getDrawing">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="getDrawingResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="return" type="ex14:DrawingType"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="contains">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="containsResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="return" type="xs:boolean"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="DrawingException">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="ex14:DrawingFault"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="SecondDrawingException">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="ex14:SecondDrawingFault"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    <xs:schema xmlns:ns1="http://lang.java_proxy" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://lang.java_proxy">
      <xs:element name="Throwable" type="ns1:ThrowableType"/>
      <xs:complexType name="ThrowableType">
        <xs:sequence>
          <xs:element name="message" type="xs:string"/>
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="getSizeRequest"/>
  <wsdl:message name="getSizeResponse">
    <wsdl:part name="parameters" element="ns:getSizeResponse"/>
  </wsdl:message>
  <wsdl:message name="addDrawingRequest">
    <wsdl:part name="parameters" element="ns:addDrawing"/>
  </wsdl:message>
  <wsdl:message name="getNamesRequest"/>
  <wsdl:message name="getNamesResponse">
    <wsdl:part name="parameters" element="ns:getNamesResponse"/>
  </wsdl:message>
  <wsdl:message name="getDrawingRequest">
    <wsdl:part name="parameters" element="ns:getDrawing"/>
  </wsdl:message>
  <wsdl:message name="getDrawingResponse">
    <wsdl:part name="parameters" element="ns:getDrawingResponse"/>
  </wsdl:message>
  <wsdl:message name="DrawingException">
    <wsdl:part name="parameters" element="ns:DrawingException"/>
  </wsdl:message>
  <wsdl:message name="SecondDrawingException">
    <wsdl:part name="parameters" element="ns:SecondDrawingException"/>
  </wsdl:message>
  <wsdl:message name="containsRequest">
    <wsdl:part name="parameters" element="ns:contains"/>
  </wsdl:message>
  <wsdl:message name="containsResponse">
    <wsdl:part name="parameters" element="ns:containsResponse"/>
  </wsdl:message>
  <wsdl:portType name="DrawingServicePortType">
    <wsdl:operation name="getSize">
      <wsdl:input message="axis2:getSizeRequest" wsaw:Action="urn:getSize"/>
      <wsdl:output message="axis2:getSizeResponse" wsaw:Action="urn:getSizeResponse"/>
    </wsdl:operation>
    <wsdl:operation name="addDrawing">
      <wsdl:input message="axis2:addDrawingRequest" wsaw:Action="urn:addDrawing"/>
    </wsdl:operation>
    <wsdl:operation name="getNames">
      <wsdl:input message="axis2:getNamesRequest" wsaw:Action="urn:getNames"/>
      <wsdl:output message="axis2:getNamesResponse" wsaw:Action="urn:getNamesResponse"/>
    </wsdl:operation>
    <wsdl:operation name="getDrawing">
      <wsdl:input message="axis2:getDrawingRequest" wsaw:Action="urn:getDrawing"/>
      <wsdl:output message="axis2:getDrawingResponse" wsaw:Action="urn:getDrawingResponse"/>
      <wsdl:fault message="axis2:DrawingException" name="DrawingException" wsaw:Action="urn:getDrawingDrawingException"/>
      <wsdl:fault message="axis2:SecondDrawingException" name="SecondDrawingException" wsaw:Action="urn:getDrawingSecondDrawingException"/>
    </wsdl:operation>
    <wsdl:operation name="contains">
      <wsdl:input message="axis2:containsRequest" wsaw:Action="urn:contains"/>
      <wsdl:output message="axis2:containsResponse" wsaw:Action="urn:containsResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="DrawingServiceSoap11Binding" type="axis2:DrawingServicePortType">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="getSize">
      <soap:operation soapAction="urn:getSize" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="addDrawing">
      <soap:operation soapAction="urn:addDrawing" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
    </wsdl:operation>
    <wsdl:operation name="getDrawing">
      <soap:operation soapAction="urn:getDrawing" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="SecondDrawingException">
        <soap:fault use="literal" name="SecondDrawingException"/>
      </wsdl:fault>
      <wsdl:fault name="DrawingException">
        <soap:fault use="literal" name="DrawingException"/>
      </wsdl:fault>
    </wsdl:operation>
    <wsdl:operation name="getNames">
      <soap:operation soapAction="urn:getNames" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="contains">
      <soap:operation soapAction="urn:contains" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="DrawingServiceSoap12Binding" type="axis2:DrawingServicePortType">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <wsdl:operation name="getSize">
      <soap12:operation soapAction="urn:getSize" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="addDrawing">
      <soap12:operation soapAction="urn:addDrawing" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
    </wsdl:operation>
    <wsdl:operation name="getDrawing">
      <soap12:operation soapAction="urn:getDrawing" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="SecondDrawingException">
        <soap12:fault use="literal" name="SecondDrawingException"/>
      </wsdl:fault>
      <wsdl:fault name="DrawingException">
        <soap12:fault use="literal" name="DrawingException"/>
      </wsdl:fault>
    </wsdl:operation>
    <wsdl:operation name="getNames">
      <soap12:operation soapAction="urn:getNames" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="contains">
      <soap12:operation soapAction="urn:contains" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="DrawingServiceHttpBinding" type="axis2:DrawingServicePortType">
    <http:binding verb="POST"/>
    <wsdl:operation name="getSize">
      <http:operation location="DrawingService/getSize"/>
      <wsdl:input>
        <mime:content type="text/xml" part="getSize"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="getSize"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="addDrawing">
      <http:operation location="DrawingService/addDrawing"/>
      <wsdl:input>
        <mime:content type="text/xml" part="addDrawing"/>
      </wsdl:input>
    </wsdl:operation>
    <wsdl:operation name="getDrawing">
      <http:operation location="DrawingService/getDrawing"/>
      <wsdl:input>
        <mime:content type="text/xml" part="getDrawing"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="getDrawing"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="getNames">
      <http:operation location="DrawingService/getNames"/>
      <wsdl:input>
        <mime:content type="text/xml" part="getNames"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="getNames"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="contains">
      <http:operation location="DrawingService/contains"/>
      <wsdl:input>
        <mime:content type="text/xml" part="contains"/>
      </wsdl:input>
      <wsdl:output>
        <mime:content type="text/xml" part="contains"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="DrawingService">
    <wsdl:port name="DrawingServiceHttpSoap11Endpoint" binding="axis2:DrawingServiceSoap11Binding">
      <soap:address location="http://10.234.10.148:8080/axis2/services/DrawingService.DrawingServiceHttpSoap11Endpoint"/>
    </wsdl:port>
    <wsdl:port name="DrawingServiceHttpSoap12Endpoint" binding="axis2:DrawingServiceSoap12Binding">
      <soap12:address location="http://10.234.10.148:8080/axis2/services/DrawingService.DrawingServiceHttpSoap12Endpoint"/>
    </wsdl:port>
    <wsdl:port name="DrawingServiceHttpEndpoint" binding="axis2:DrawingServiceHttpBinding">
      <http:address location="http://10.234.10.148:8080/axis2/services/DrawingService.DrawingServiceHttpEndpoint"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>